import React, { Dispatch, Reducer, useCallback, useContext, useReducer } from 'react';
import { main } from 'wailsjs/go/models';
import { IEditorInfo } from './views/EditorView/IEditorInfo';
import { Slot, Workspaces } from './views/WorkspacesView';

export namespace GlobalValue {
  export interface IEditorsSlotInfo {
    id: string;
    editors: IEditorInfo[];
    actived?: IEditorInfo;
  }
  export interface IChatlogState {
    wx_instances?: main.Account[],
    account?: string,
    status?: string,
    pid?: string;
    cur_wx?: main.Account,
    data_usage?: string,
    data_dir?: string,
    work_usage?: string,
    work_dir?: string,
    auto_decrypt?: boolean,
    http_enabled?: boolean,
    http_addr?: string,
    platform?: string,
    fullVersion?: string,
    exePath?: string,
    data_key?: string,
    img_key?: string,
  }
  class State {
    smallScreen: boolean | undefined = false;
    favorite_nav_paths: string[] = [];
    slot_infos: { [x in string]?: IEditorsSlotInfo } = {};
    actived_slot?: Slot;
    workspaces?: Workspaces;
    chatlog_state?: IChatlogState
  }
  export function Provider(props: React.PropsWithChildren) {
    const [state, dispatch] = useReducer(_reducer, defaulValue);
    current_state = state
    return <context.Provider value={[state, dispatch]} {...props} />;
  }

  export function use(): [State, TSetValue, React.Dispatch<Action<Type>>];
  export function use(mode: 0): State;
  export function use(mode: 1): TSetValue;
  export function use(mode?: 0 | 1): any {
    const [state, dispatch] = useContext(context)
    if (mode === 0) return state
    const setValue = useCallback<TSetValue>((k, v) => dispatch([Type.SetValue, [k, v]]), [])
    if (mode === 1) return setValue
    return [state, setValue, dispatch]
  }

  const defaulValue = new State();
  export let current_state = defaulValue
  export enum Type {
    SetValue = 'set_value',
    SetSlotInfos = 'set_slot_infos',
    DelSlotInfos = 'del_slot_infos',
    SetActivedSlot = 'set_actived_slot',
    AddEditor = 'add_editor'
  }
  export type TSetValue<K extends keyof State = keyof State> = (key: K, value: State[K]) => void
  export type Payload_SetValue<K extends keyof State = keyof State> = [K, State[K]];

  export interface TypePayloadMap {
    [Type.SetValue]: Payload_SetValue;
    [Type.SetSlotInfos]: IEditorsSlotInfo[];
    [Type.DelSlotInfos]: string[];
    [Type.SetActivedSlot]: Slot;
    [Type.AddEditor]: [string, IEditorInfo]
  }

  type Action<K extends keyof TypePayloadMap = keyof TypePayloadMap> = [K, TypePayloadMap[K]]
  export const _reducer: Reducer<State, Action> = (state, action) => {
    const [type, payload] = action;
    switch (type) {
      case Type.SetValue: {
        const [k, v] = payload as TypePayloadMap[Type.SetValue];
        return { ...state, [k]: v };
      }
      case Type.SetSlotInfos: {
        const slots = payload as TypePayloadMap[Type.SetSlotInfos];
        if (!slots.length) return state

        const slot_infos = { ...state.slot_infos }
        for (const slot of slots) {
          if (!slot.editors.length) delete slot_infos[slot.id]
          else slot_infos[slot.id] = { ...slot, editors: [...slot.editors] }
        }
        const ret: State = {
          ...state,
          slot_infos,
          actived_slot: state.workspaces?.leaves.find(v => v.id === slots[slots.length - 1].id)
        }
        return ret;
      }
      case Type.DelSlotInfos: {
        const slot_ids = payload as TypePayloadMap[Type.DelSlotInfos];
        const slot_infos = { ...state.slot_infos }
        for (const slot_id of slot_ids)
          delete slot_infos[slot_id]
        return { ...state, slot_infos };
      }

      case Type.SetActivedSlot: {
        const actived_slot = payload as TypePayloadMap[Type.SetActivedSlot];
        return { ...state, actived_slot }
      }
    }
    return state;
  };

  const context = React.createContext([defaulValue, () => void 0] as [State, Dispatch<Action>]);
  context.displayName = "GlobalValue";
}
